using Autofac;
using Autofac.Extensions.DependencyInjection;
using EMall.Middlewares;
using EMall.Query;
using Microsoft.AspNetCore.Rewrite;
using Microsoft.CodeAnalysis;
using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi.Models;
using Serilog;
using System.Reflection;
using Yarp.ReverseProxy.Configuration;

namespace EMall.AdminGateway
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var allAssemblies = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "EMall*.dll")
               .Select(o => Assembly.Load(AssemblyName.GetAssemblyName(o))).ToList();
            var builder = WebApplication.CreateBuilder(args);
            builder.Host.UseSerilog((hostBuilderContext, serviceProvider, loggerConfiguration) =>
            {
                loggerConfiguration.ReadFrom.Configuration(hostBuilderContext.Configuration);
            });
            builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureContainer<ContainerBuilder>(containerBuilder =>
                {
                    var assemblies = allAssemblies.ToArray();
                    #region QueryServices
                    containerBuilder.RegisterAssemblyTypes(assemblies)
                    .Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(typeof(IQueryService)) && t.Name.EndsWith("QueryService"))
                    .AsImplementedInterfaces().InstancePerLifetimeScope();
                    #endregion
                });
            builder.Services.AddControllers();
            builder.Services.AddCors(options =>
            {
                var origins = builder.Configuration.GetSection("Cors").Value!.Split(",");
                options.AddDefaultPolicy(config =>
                {
                    config
                    .WithOrigins(origins)
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
                });
            });
            builder.Services.AddDbContext<IdentityServerDbContext>(options =>
            {
                options.UseSqlite(builder.Configuration.GetConnectionString("Sqlite"),
                    builder => builder.MigrationsAssembly(Assembly.GetExecutingAssembly().GetName().Name));
                //options.UseMySql(
                //    builder.Configuration.GetConnectionString("Default"),
                //    MySqlServerVersion.LatestSupportedServerVersion,
                //    builder => builder.MigrationsAssembly(Assembly.GetExecutingAssembly().GetName().Name));
            });
            builder.Services.AddReverseProxy().LoadFromStore();
            builder.Services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo
                {
                    Title = "EMall Admin Gateway",
                    Version = "v1"
                });
                options.DocInclusionPredicate((docName, description) => true);
                options.CustomSchemaIds(type => type.FullName);
            });
            var app = builder.Build();
            app.UseCors();
            app.UseRequestLogging();
            app.UseSwagger();
            app.UseSwaggerUI(options =>
            {
                var yarpConfig = app.Services.GetRequiredService<IProxyConfigProvider>().GetConfig();
                var routedClusters = yarpConfig.Clusters.SelectMany(t => t.Destinations, (clusterId, destination) => new { clusterId.ClusterId, destination.Value });
                var groupedClusters = routedClusters.GroupBy(q => q.Value.Address).Select(t => t.First()).Distinct().ToList();
                foreach (var clusterGroup in groupedClusters)
                {
                    var routeConfig = yarpConfig.Routes.FirstOrDefault(q => q.ClusterId == clusterGroup.ClusterId);
                    if (routeConfig == null)
                    {
                        continue;
                    }
                    options.SwaggerEndpoint($"{clusterGroup.Value.Address}/swagger/v1/swagger.json", $"{routeConfig.ClusterId} API");
                    //options.OAuthClientId(builder.Configuration["AuthServer:SwaggerClientId"]);
                    //options.OAuthClientSecret(builder.Configuration["AuthServer:SwaggerClientSecret"]);
                }
            });
            app.UseRewriter(new RewriteOptions().AddRedirect("^(|\\|\\s+)$", "/swagger"));
            app.MapReverseProxy();
            app.Run();
        }
    }
}
